﻿/*--------------------------------------------------
 Creater：Junxuan.Su
 Time：2012-9-11 9:53:47
 Remark : WhereIfExtension
--------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace HXDNB.Infrastructure.Extension
{
    public static class LinqExtensions
    {
        public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate, bool condition)
        {
            return condition ? source.Where(predicate) : source;
        }

        public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool condition)
        {
            return condition ? source.Where(predicate) : source;
        }

        public static IQueryable<T> OrderByIf<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey>> predicate, bool condition)
        {
            return condition ? source.OrderBy(predicate) : source;
        }

        public static IEnumerable<T> OrderByIf<T, TKey>(this IEnumerable<T> source, Func<T, TKey> predicate, bool condition)
        {
            return condition ? source.OrderBy(predicate) : source;
        }

        public static IQueryable<T> OrderByDescendingIf<T, TKey>(this IQueryable<T> source, Expression<Func<T, TKey>> predicate, bool condition)
        {
            return condition ? source.OrderByDescending(predicate) : source;
        }

        public static IEnumerable<T> OrderByDescendingIf<T, TKey>(this IEnumerable<T> source, Func<T, TKey> predicate, bool condition)
        {
            return condition ? source.OrderByDescending(predicate) : source;
        }

        public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
        {
            return source.Distinct(Equality<T>.CreateComparer(keySelector));
        }

        public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer)
        {
            return source.Distinct(Equality<T>.CreateComparer(keySelector, comparer));
        }

        public static IQueryable<T> WhereIn<T, TValue>(this IQueryable<T> query, Expression<Func<T, TValue>> obj, IEnumerable<TValue> values)
        {
            return query.Where(BuildWhereInExpression(obj, values));
        }

        private static Expression<Func<TElement, bool>> BuildWhereInExpression<TElement, TValue>(Expression<Func<TElement, TValue>> propertySelector, IEnumerable<TValue> values)
        {
            var p = propertySelector.Parameters.Single();
            var list = values.ToList();
            if (!list.Any())
                return e => false;

            var equals = list.Select(value => (Expression)Expression.Equal(propertySelector.Body, Expression.Constant(value, typeof(TValue))));
            var body = equals.Aggregate(Expression.Or);

            return Expression.Lambda<Func<TElement, bool>>(body, p);
        }
    }
}
